//
//  DataLoader.m
//  ClienteHabitueIOS
//
//  Created by Mauro Carreño on 6/1/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "DataLoader.h"
#import "JSON.h"
#import "SharedMemory.h"
#import "ControlVariables.h"
#import "DataLoaderConnection.h"
#import "MBProgressHUD.h"
#import "Reachability.h"
#import "User.h"
#import "PointOfSell.h"
#import "AuditType.h"
#import "Toast+UIView.h"

@implementation DataLoader

@synthesize successSelector;
@synthesize failureSelector;
@synthesize callerOfSelector;
@synthesize connections;
@synthesize callType;
@synthesize remainingParsing;
@synthesize isUsingHistory;
@synthesize historyFileName;
@synthesize isReadingFromHistory;


static NSString* UrlBaseGeneral;

static NSString* URL_USER_LIST = @"%@/auditor"; //GET
static NSString* URL_ADD_POINTOFSALE = @"%@/pointofsell"; //POST json
static NSString* URL_GET_POINTSOFSALE = @"%@/comment/%@"; //GET + userId or POST + latitude + longitude (optional)
static NSString* URL_ADD_AUDIT = @"%@/audit"; //POST json
static NSString* URL_GET_AUDIT_TYPES = @"%@/audittype/%@"; //GET  + userId
//static NSString* URL_GET_COMMENTS = @"%@/comment"; //GET


+ (void) setUrlBaseGeneral:(NSString*)aUrlBaseGeneral{
    UrlBaseGeneral = aUrlBaseGeneral;
}
+ (NSString*) urlBaseGeneral{
    return UrlBaseGeneral;
}

- (void) dealloc
{
    //NSLog(@"Deleting dataloader: %@",self);
    [self releaseConnections];
    [connections release], connections = nil;
    [callerOfSelector release], callerOfSelector = nil  ;
    if(self.historyFileName){[historyFileName release], historyFileName = nil; }
    [super dealloc];
}

- (void) releaseConnections
{
    for (DataLoaderConnection *dlcon in self.connections) {
        [dlcon cancelAllCalls];
    }
    [self.connections removeAllObjects];
}

- (id) initWithCaller:(id)caller successSel:(SEL)successTaget failureSel:(SEL) failureTarget
{
    self = [super init];
    self.successSelector = successTaget;
    self.failureSelector = failureTarget;
    self.callerOfSelector = caller;
    self.connections = [[[NSMutableArray alloc] init] autorelease];
    self.historyFileName = nil;
    self.isUsingHistory = false;
    self.isReadingFromHistory = false;
    return self;
}

-(void)localLoad:(NSString*)data_string OfType:(int)type andResponseCode:(NSInteger)responseCode andDataLoaderConnection:(DataLoaderConnection*) dataLoaderConnection;
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) {
        [self parseData:data_string OfType:type andResponseCode:responseCode andDataLoaderConnection:dataLoaderConnection];
    });
}


- (void) genericCall:(int)_calltype loginUrl:(NSString*)loginUrl dataToPost:(NSString*) dataToPost debugFileName:(NSString*) debugFileName
{
    self.callType = _calltype;
    remainingParsing = 1;
    [self releaseConnections];
    if (DEBUG_LOCAL == YES) {
        NSString *areasCon = [[[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:debugFileName ofType:@"json"] encoding:NSUTF8StringEncoding error:nil] autorelease];
        [self localLoad:areasCon OfType:self.callType andResponseCode:0 andDataLoaderConnection:nil];
    }
    else {
        [self.connections addObject:[[[DataLoaderConnection alloc] initPostWithCaller:self  failSel:@selector(dataNotReady:)  URL:loginUrl type:self.callType data:dataToPost] autorelease]];
    }
}


//GET
- (void) loadUsers
{
    self.isUsingHistory = true;
    self.historyFileName = @"USERS_HISTORYFILE.txt";
    [self genericCall:TYPE_USER_LIST loginUrl:[NSString stringWithFormat:URL_USER_LIST,UrlBaseGeneral] dataToPost:nil debugFileName:@"userTest1"];
}


//GET or POST
- (void) loadPointsOfSell:(CLLocation*)location
{
    self.isUsingHistory = true;
    self.historyFileName = @"PDVS_HISTORYFILE.txt";
    NSString* post = nil;
    if (location!=nil) {
        CLLocationCoordinate2D cord = [location coordinate];
        post=[NSString stringWithFormat:@" { \"longitude\": %f, \"latitude\": %f }",cord.longitude,cord.latitude];
    }
    [self genericCall:TYPE_GET_POINTSOFSALE loginUrl:[NSString stringWithFormat:URL_GET_POINTSOFSALE,UrlBaseGeneral,[[SharedMemory sharedInstance] getUser].externalId ] dataToPost:post debugFileName:@"pointsOfSellTest1"];
}


//GET
- (void) loadAuditTypes
{
    self.isUsingHistory = true;
    self.historyFileName = @"AUDITTYPES_HISTORYFILE.txt";
    [self genericCall:TYPE_GET_AUDIT_TYPES loginUrl:[NSString stringWithFormat:URL_GET_AUDIT_TYPES,UrlBaseGeneral,[[SharedMemory sharedInstance] getUser].externalId ] dataToPost:nil debugFileName:@"auditTypesTest1"];
}



//POST
- (void) postPointOfSell:(NSString*) json
{
    [self genericCall:TYPE_ADD_POINTOFSALE loginUrl:[NSString stringWithFormat:URL_ADD_POINTOFSALE,UrlBaseGeneral ] dataToPost:json debugFileName:@"statusSuccess"];
}


//POST
- (void) postAudit:(NSString*) json
{
    [self genericCall:TYPE_ADD_AUDIT loginUrl:[NSString stringWithFormat:URL_ADD_AUDIT,UrlBaseGeneral ] dataToPost:json debugFileName:@"statusSuccess"];
}



-(void) parseData:(NSString*)data_string OfType:(int)type andResponseCode:(NSInteger)responseCode andDataLoaderConnection:(DataLoaderConnection*) dataLoaderConnection;
{
    /*
    if (dataLoaderConnection)
        [dataLoaderConnection release];
     */
    
    //JSON types
    if (type < 100) {
        // First try to JSON parse it
        // Create SBJSON object to parse JSON
        SBJSON *parser = [[SBJSON alloc] init];
        
        NSArray* jsonArray = [parser objectWithString:data_string error:nil];
        [parser release];
        
        //Response should be JSON type
        if (jsonArray!=nil) {
            @try {
                //will try to parse the JSON and call the DataReady
                [self parseJSONData:jsonArray OfType:type];
                //If its using History and not currently reading from a file, then it rewrites the history file.
                if (self.isUsingHistory && !self.isReadingFromHistory) {
                    [SharedMemory createTextFile:self.historyFileName data:data_string];
                }
            }
            @catch (NSException * e) {
                NSLog(@"SERVER RESPONDED WITH UNKNOWN DATA OR PARSER DIED.\n\nTYPE:%d\n\nRESPONSE:%@\n\nEXCEPTION:%@",type,data_string,e);
                [self exitWithErrorTitle:kErrorMessageJsonTitle message:kErrorMessageJson];
            }
            @finally {
                //Anyway it should exit
                return;
            }
        }
        
        NSLog(@"SERVER RESPONDED WITH UNKNOWN DATA.\n\nTYPE:%d\n\nRESPONSE:%@",type,data_string);
        return [self exitWithErrorTitle:kErrorMessageJsonTitle message:kErrorMessageJson];
    }
    //HTML types
    else if (type < 200) {
        //Response codes of kind 2xx are successful
        if (200 > responseCode || responseCode >= 300 ) {
            NSLog(@"SERVER RESPONDED WITH ERROR CODE.\n\nTYPE:%d\n\ERROR_CODE:%d\n\nRESPONSE:%@",type,responseCode,data_string);
            return [self exitWithErrorTitle:kErrorHTTPResponseTitle message:kErrorHTTPResponse];
        }
        remainingParsing--;
        [self dataReady:nil];
        return;
    }

}



-(void) parseJSONData:(NSArray*) jsonArray OfType:(int)loadType
{
    SharedMemory *mem = [SharedMemory sharedInstance];
    
    //NSLog(@"response: %@", [jsonArray description]);
    NSString* jsonArrayValueString;
    
    switch (loadType){
            
        case TYPE_ADD_POINTOFSALE:
            jsonArrayValueString = [jsonArray objectAtIndex:0];
            PointOfSell* pdv = [SharedMemory findPDVByInternalId:mem.commitPointOfSellInternalId];
            pdv.externalId = jsonArrayValueString;
            break;
            
        case TYPE_ADD_AUDIT:
            //jsonArrayValueString = jsonObject.optString("value");
            //TODO: ver que devuelve Alan. De momento los errores devuelven HTML no paseable por lo que funciona bien.
            break;
            
        case TYPE_USER_LIST:
            [mem.users removeAllObjects];
            [self genericArrayAction:jsonArray OfType:loadType];
            break;
            
        case TYPE_GET_POINTSOFSALE:
            [mem.pointsOfSell removeAllObjects];
            [self genericArrayAction:jsonArray OfType:loadType];
            //Update the last fetch date
            if (!self.isReadingFromHistory)
                [SharedMemory rememberTodayOn:SHARED_PREFS_LAST_FETCH];
            break;
            
        case TYPE_GET_AUDIT_TYPES:
            [mem.auditTypes removeAllObjects];
            [mem.auditTypesDone removeAllObjects];
            [self genericArrayAction:jsonArray OfType:loadType];
            for (NSObject* o in mem.auditTypes)
                [mem.auditTypesDone addObject:[NSNumber numberWithBool:false]];
            break;
            
        default:
            break;
    }
    
    //NSLog(@"  parsed:%i",type);
    remainingParsing--;
    [self dataReady:nil];
}


- (void) genericArrayAction:(NSArray*) jsonArray OfType:(int)loadType
{
    SharedMemory *mem = [SharedMemory sharedInstance];
    //JSONArray jsonArray = jsonObject.getJSONArray("value");
    for (int i = 0; i < [jsonArray count]; i++) {
        NSDictionary* jsonArrayObject = [jsonArray objectAtIndex:i];
        
        switch (loadType){
                
			case TYPE_USER_LIST:
				[mem.users addObject: [[[User alloc] initWithDictionary:jsonArrayObject] autorelease] ];
				break;
				
			case TYPE_GET_POINTSOFSALE:
                [mem.pointsOfSell addObject: [[[PointOfSell alloc] initWithDictionary:jsonArrayObject] autorelease] ];
				break;
				
			case TYPE_GET_AUDIT_TYPES:{
                AuditType *aud = [ [[AuditType alloc] initWithDictionary:jsonArrayObject] autorelease];
                if ([mem getUser].traderMKT==aud.tradeMKT)
                    [mem.auditTypes addObject: aud];
				break;
            }
			default:
				break;
        }
    }
}


- (void) dataReady:(DataLoaderConnection*) dataLoaderConnection;
{
    //Success case, when there are no remaining parsings, ir calls the return selector.
    if (remainingParsing ==0){
        [self.callerOfSelector performSelectorOnMainThread:self.successSelector withObject:self waitUntilDone:false];
        //[self.callerOfSelector performSelector:self.successSelector withObject:self];
    }
}

- (void) dataNotReady:(DataLoaderConnection*) dataLoaderConnection;
{
    //Possibly reading from history
    if (self.isUsingHistory && !self.isReadingFromHistory) {
        self.isReadingFromHistory = true;
        NSString *filePath = [[SharedMemory getDocumentsDir] stringByAppendingPathComponent:self.historyFileName];
        NSString* jsonString = [[[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] autorelease];
        if (jsonString!=nil && ![jsonString isEqualToString:@""]) {
            @try {
                //Tries to show a Toast. If it cant then it doesnt matter.
                [((UIViewController*)self.callerOfSelector).view makeToast:kWarningUsingHistory];
            }
            @catch (NSException *exception) {
            }
            [self localLoad:jsonString OfType:self.callType andResponseCode:0 andDataLoaderConnection:dataLoaderConnection];
            return;
        }
    }
    
    if (remainingParsing !=-1){
        remainingParsing = -1;
        [self.callerOfSelector performSelectorOnMainThread:self.failureSelector  withObject:self waitUntilDone:false];
    }
}

- (void) exitWithErrorTitle:(NSString*)title message:(NSString*)message
{
    SharedMemory *mem = [SharedMemory sharedInstance];
    mem.errorMessage = message;
    mem.errorMessageTitle = title;  
    [self.callerOfSelector performSelectorOnMainThread:self.failureSelector  withObject:self waitUntilDone:false];
}


#pragma mark - Connection

+ (BOOL) connectedToNetwork
{ 
	Reachability *r = [Reachability reachabilityWithHostName:@"www.google.com"];
	NetworkStatus internetStatus = [r currentReachabilityStatus];
	BOOL internet;
	if (internetStatus == NotReachable)  {
		internet = NO;
	} else {
		internet = YES;
	}
	return internet;
} 

+(BOOL) checkInternet
{
	//Make sure we have internet connectivity
	if([DataLoader connectedToNetwork] != YES){
        SharedMemory *mem = [SharedMemory sharedInstance];
        mem.errorMessage = kErrorInternetConnection;
        mem.errorMessageTitle = kErrorInternetConnectionTitle;
		return NO;
	}
	else {
		return YES;
	}
}

+ (bool) isNull:(id)obj
{
    if (obj == nil || obj == [NSNull null] || ([obj isKindOfClass:[NSString class]] && ([obj isEqualToString:@"<null>"] || [obj isEqualToString:@""]))) {
        return true;
    }
    return false;
}



@end
